#ifndef _MULTI_TYPE_TABLE_JM_2011_08_29_
#define _MULTI_TYPE_TABLE_JM_2011_08_29_


namespace jm4bbx {

template<typename Key>
class MultiTypeTable {
    public:
        typedef std::vector<Key> KeyConatiner;
        typedef std::string CellType;
        typedef std::vector<CellType> CellContainer;
        typedef std::vector<CellContainer> ColumnContainer;

        MultiTypeTable() : keyColumnIndex_(0) {}
        MultiTypeTable(size_t keyColumnIndex) : keyColumnIndex_(keyColumnIndex) { }
        MultiTypeTable(size_t keyColumnIndex, const ColumnContainer& data) : keyColumnIndex_(keyColumnIndex) {      
            setTable(data);
        }

        virtual ~MultiTypeTable() { }

        void setKeyColumnIndex(size_t i) { keyColumnIndex_ = i;}
        size_t getKeyColumnIndex() const { return keyColumnIndex_;}

        void setTable(const ColumnContainer& data) {
            table_ = data;
            for(size_t i = 0; i < data.size(); ++i) {                
                    keyColumn_.push_back(getTypedKeyValue(data[i][keyColumnIndex_]));                
            };
        }

        const CellType& getCell(size_t row, size_t col) const {
            return table_[row][col];
        }


        void setCell(size_t row, size_t col, const CellType& v) {
            if (keyColumnIndex_ == col) {
                keyColumn_[row] = getTypedKeyValue(v);
            }
            table_[row][col] = v;;
        }


        const CellContainer& getLine(size_t row) const {
            return table_[row];
        }

       void setLine(size_t row, const CellContainer& line) {
            table_[row] = line;
            keyColumn_[row] = getTypedKeyValue(line[keyColumnIndex_]);
        }

        void addLine(const CellContainer& line) {
            table_.push_back(line);
            keyColumn_.push_back(getTypedKeyValue(line[keyColumnIndex_]));
        }


        Key getKey(size_t row) const {
            return keyColumn_[row];
        }

        Key getTypedKeyValue(const CellType& v) const {
            std::stringstream stream;
            stream << v;
            Key key;
            stream >> key;
            return key;        
        }

        /// number of rows
        size_t size() const {
            return table_.size();
        }

        /// line length == count of columns
        size_t size(size_t row) const {
            return table_[row].size();
        }

        void clear() {
            table_.clear();
        }

        template<typename T>
        void dumpKeys(T& container) {
            container.resize(keyColumn_.size());
            std::copy(keyColumn_.begin(), keyColumn_.end(), container.begin());
        }

    protected:
        
    private:
        size_t keyColumnIndex_;
        KeyConatiner keyColumn_;
        ColumnContainer table_;
};

} // namespace jm

#endif
